package httplib;

import java.util.ArrayList;

import util.ConcurrentAccess;
import util.ExecUtil;

/**
 * This class represents a Thread object which handles a single HTTP Request
 *
 */
public class HTTPProtocol  {

	private HTMLFileHandler fileHandler;
	private ConcurrentAccess access;

	//private String httpText;
	private ArrayList<String> tokens;
	private String host;

	private String headerData = "";

	public HTTPProtocol(){
		access = ConcurrentAccess.getInstance();
	}
	
	public byte[] processInput(String request){

		String[] http = request.split(" |\n");
		tokens = new ArrayList<String>();
		//hosts = new ArrayList<String>();
		
		for (int i=0; i<http.length ; i++){
			tokens.add(http[i]);
		}
		
		//Check if the request is for an executable file (filename.exe)
		if (tokens.get(0).split(".")[1].equals("exe")){
			ExecUtil exec = new ExecUtil(tokens.get(0));
			exec.execute();
		}
		
		//If there is more data beyond the normal request, it means it's header data
		//In that case, save it
		if (http.length > 4){
			for (int j=5; j<http.length; j++){
				this.headerData = this.headerData.concat(http[j]) + " ";
			}
		}


		//If bad HTTP version, do not bother processing the request
		if (!(getProtocol().equals(HTTPConstants.HTTPVersion))){
			return prepareAndSendResponse(HTTPConstants.BAD_VERSION_STATUS);
		}

		//Print out parts of the URI to the console
		System.out.println(getCommand() + " Host: " + host + " LocalPath: " + 
				getLocalUri() + " Filename: " + getFileName() + "\n");

		//If GET, read from a file
		if (getCommand().equals(HTTPConstants.GET)){
			fileHandler = new HtmlReader();
			String message = access.get(fileHandler, getFileName());
			return prepareAndSendResponse(message);
		}else if (getCommand().equals(HTTPConstants.PUT)){
			fileHandler = new HtmlWriter(getFileName());
			String message = access.put(fileHandler, getHeaderData());
			return prepareAndSendResponse(message);
			
		} else {
			return prepareAndSendResponse(HTTPConstants.HTTPVersion + " " + 
					HTTPConstants.BAD_REQ_STATUS + " " + HTTPConstants.BAD_REQ_STATUS_MSG + 
					"\n" + HTTPConstants.RESPONSE_HEADER + "0");
		}
	}

	/**
	 * After the request is processed, send it back to the parent program
	 * @param message
	 */
	private byte[] prepareAndSendResponse(String message){
		if (message.equals(HTTPConstants.NOT_FOUND_STATUS)){
			return sendNotFoundMessage();
		} else if (message.equals(HTTPConstants.BAD_VERSION_STATUS)){
			return sendBadVersionResponse();
		} else if (message.equals(HTTPConstants.OK_STATUS)){
			return getOKResponse();
		} else{
			return message.getBytes();
		}
	}

	/**
	 * 
	 * @return HTTP version
	 */
	private String getProtocol(){
		return this.tokens.get(2);
	}

	/**
	 * 
	 * @return GET/PUT
	 */
	private String getCommand(){
		return this.tokens.get(0);
	}

	/**
	 * Sends a message to the parent program, saying that the requested file was not found
	 */
	private byte[] sendNotFoundMessage(){
		return(HTTPConstants.HTTPVersion + " " + HTTPConstants.NOT_FOUND_STATUS 
				+ " " + HTTPConstants.NOT_FOUND_STATUS_MSG + "\n" + HTTPConstants.CONTENT_LENGTH + "0").getBytes();
	}

	/**
	 * Sends a message to the parent program, saying that the HTTP version was unsupported
	 */
	private byte[] sendBadVersionResponse(){
		return (HTTPConstants.HTTPVersion + " " + HTTPConstants.BAD_VERSION_STATUS
				+ " " + HTTPConstants.BAD_VERSION_STATUS_MESSAGE + "\n" + 
				HTTPConstants.RESPONSE_HEADER + "0").getBytes();
	}

	/**
	 * Sends a message to the parent program, saying that the request was processed successfully
	 */
	private byte[] getOKResponse(){
		byte[] header = fileHandler.getResponseHeader().getBytes();
		byte[] response = fileHandler.getResponseFile();
		
		int c = 0;
		byte[] retArray = new byte[header.length + response.length];
		for (int k=0; k<header.length; k++){
			retArray[k] = header[k];
		}
		for (int j=header.length; j<retArray.length; j++){
			retArray[j] = response[c];
			c++;
		}
		return retArray;
	}

	/**
	 * Output all the tokens of this HTTP request, for testing purposes
	 */
	public void outputTokens(){
		for (String string:tokens) System.out.println(string);
	}



	/**
	 * 
	 * @return The local path
	 */
	public String getLocalUri(){
		return this.tokens.get(1);
	}
	
	/**
	 * 
	 * @return the local file name
	 */
	public String getFileName(){
		String[] uri = getLocalUri().split("/");
		return uri[uri.length-1];
	}

	public String getHeaderData(){
		return this.headerData;
	}

}
